<template>
  <div class="ElTableBox" :id="tableId" v-loading="loading" element-loading-text="数据加载中...">
    <div class="ElTbodyBox" :style="{
      height: typeof height === 'number' ? proxy.$size(isSearch ? height - 40 : height) : height
    }" v-if="$slots.item">
      <el-scrollbar>
        <FlexListBox class="p-12" :data="tbody" :list="tbodyList" v-if="tbodyList">
          <template #item="{ row }">
            <slot name='item' :row="row" />
          </template>
        </FlexListBox>
        <template v-else>
          <template v-for="item in tbody">
            <slot name='item' :row="item" />
          </template>
        </template>
      </el-scrollbar>
    </div>
    <el-table ref="TableRef" :height="typeof height === 'number' ? isSearch ? height - 40 : height : height"
      :max-height="maxHeight" border :highlight-current-row="isHighlight" :data="tbody" :span-method="spanMethod"
      :show-summary="Array.isArray(summary) && summary.length > 0" :summary-method="getSummaries" :row-key="rowKey"
      size="default" @selection-change="handleSelectionChange" @header-dragend="headerDragend" @row-dblclick="dblclick"
      @cell-click="cellClick" :style="{
        width: proxy.$size(width, '100%'),
      }" @row-click="rowClick" :row-class-name="tableRowClassName" v-else>
      <template v-if="isCheckbox || isRadio">
        <el-table-column type="selection" fixed="left" align="center" :selectable="selectable" width="40"
          v-if="isCheckbox" />
        <el-table-column label="单选" fixed="left" align="center" width="70" v-if="isRadio">
          <template #default="scope">
            <el-link type="primary" @click="tableRadioBtn(scope.row)"
              :disabled="selectable ? !selectable(scope.row) : false">选择</el-link>
          </template>
        </el-table-column>
      </template>
      <template v-else-if="sortKey && !disabled">
        <el-table-column label="排序" fixed="left" align="center" width="60">
          <template #default="scope">
            <div class="iconfont icon-yidonghengbeifen7 pointer" title="长按拖拽排序"></div>
          </template>
        </el-table-column>
      </template>
      <el-table-column label="序号" type="index" fixed="left" align="center" width="60" v-else>
        <template #default="scope">
          {{ search && search.pageIndex && search.pageSize && search.pageIndex > 1 ? (search.pageIndex - 1) *
            search.pageSize +
            scope.$index + 1 :
            scope.$index + 1 }}
        </template>
      </el-table-column>
      <template v-for="item in thead || []" :key="item.prop">
        <template v-if="!item.hidden">
          <ElTableColumnBox :data="item" :search="search" :disabled="disabled" @changeBtn="changeBtn"
            @clickHeadBtn="clickHeadBtn">
            <template #[key]="{ row, index }" v-for="(slot, key) in $slots" :key="key">
              <slot :name="key" :row="row" :index="index" v-if="!keyNotArr.includes(key)" />
            </template>
          </ElTableColumnBox>
        </template>
      </template>
      <el-table-column label="操作" fixed="right" align="center" width="80" v-if="$slots.operation">
        <template #header="scope">
          <div class="columnHead" @click="
            () => {
              copyJsonToClipboard(thead);
            }
          ">
            <p>操作</p>
          </div>
        </template>
        <template #default="scope">
          <slot name="operation" :row="scope.row" :index="scope.$index" />
        </template>
      </el-table-column>
    </el-table>
    <div class="pagination" :style="{
      padding: height ? '8px' : 0,
    }" v-if="isSearch">
      <div class="tableBox-left">
        <div class="tableBox-totalCount">
          <span>共有</span>
          <span class="text-color-primary">{{ search.totalCount || 0 }}</span>
          <span>条</span>
        </div>
        <template v-if="isCheckbox">
          <el-divider direction="vertical" />
          <div class="tableBox-totalCount">
            <span>已选</span>
            <span class="text-color-primary">{{ dataInfo?.checkboxArr?.length || 0 }}</span>
            <span>条</span>
          </div>
          <el-button size="small" @click="toggleSelection(tbody)">反选</el-button>
          <el-button size="small" @click="toggleSelection()">清空</el-button>
        </template>
      </div>
      <el-pagination background size="small" v-model:current-page="search.pageIndex" v-model:page-size="search.pageSize"
        :teleported=false :page-sizes="[30, 100, 200, 300, 400]" layout="sizes,prev, pager, next,jumper"
        :total="search.totalCount" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
    </div>
  </div>
</template>
<script setup lang="ts">
//获取当前实例
import { getCurrentInstance, onMounted, ref } from 'vue';
const { proxy } = getCurrentInstance() as any;
//获取父级数据
const props = withDefaults(
  defineProps<{
    tableId?: string,//表格ID，用于页面表格排序使用
    tbody?: any; //列表数据
    thead?: any; //表头
    height?: number | string; //高度
    maxHeight?: number | string; //高度
    width?: number | string; //宽度
    size?: string; //宽度
    summary?: any; //合计字段
    isHighlight?: boolean; //是否高亮
    disabled?: boolean; //是否禁用
    loading?: boolean; //是否加载
    rowKey?: string; //
    selectable?: Function; // CheckBox 是否允许勾选
    search?: any; // 搜索分页信息
    isCheckbox?: any; // 是否多选
    isRadio?: any; // 是否单选
    sortKey?: any; // 排序编号
    sortTitle?: Function; // 排序标题
    spanMethod?: Function; // 合并行或列的计算方法
    tbodyList?: number; // 列数
    selectArr?: any; // 选中列表
  }>(),
  {
    tbody: [],
    thead: [],
    summary: [],
    selectArr: [],
    rowKey: 'rowId',
    tableId: 'tableId',
  },
);
watch(() => props.selectArr, (newVal, oldVal) => {
  if (Array.isArray(props.selectArr) && props.selectArr.length > 0) {
    toggleSelection()
    toggleSelection(props.selectArr, true)
  }
});

const getSummaries = (param: any) => {
  const { columns, data } = param
  const sums: (string | VNode)[] = []
  columns.forEach((column: any, index: any) => {
    if (index === 0) {
      sums[index] = h('div', { style: { textDecoration: 'underline' } }, [
        '',
      ])
      return
    }
    const summaryKey = props.summary.map((el: any) => el.value)
    const summaryRow = props.summary.find((el: any) => el.value === column.property) || {}
    const values = data.map((item: any) => {
      if (summaryKey.includes(column.property)) {
        return Number(item[column.property])
      } else {
        return NaN
      }
    })
    if (!values.every((value: any) => Number.isNaN(value) && summaryRow)) {
      sums[index] = proxy.$arrTotal(values, '', summaryRow.isAverage)
    } else {
      sums[index] = ''
    }
  })
  return sums
}
const TableRef = ref(null);
const dataInfo: any = reactive({
  checkboxArr: [],
  keyNotArr: ['search', 'header', 'operation'],
  checkboxList: [],
});
const isSearch = computed(() => {
  let _search = props.search
  return _search && _search.pageIndex && _search.pageSize
})

const keyNotArr = ref(['search', 'header', 'operation']);
const emit = defineEmits<{
  //fn为父组件引入子组件是定义的子组件事件属性，可随意定义
  (event: 'searchBtn'): void;
  (event: 'handleSelectionChange', arr: any[]): void;
  (event: 'headerDragend', key: string, newWidth: number): void;
  (event: 'dblclick', row: any, column: any): void;
  (event: 'tableRadioBtn', row: any): void;
  (event: 'rowClick', row: any): void;
  (event: 'tableCheckboxBtn', row: any[]): void;
  (event: 'cellClick', key: string, value: any): void;
  (event: 'changeBtn', value: any, row: any, option: any): void;
  (event: 'toggleSelection'): void;
  (event: 'onSort', evt: any): void;
}>();
const tableRowClassName = ({
  row,
  rowIndex,
}: {
  row: any
  rowIndex: number
}) => {
  if (!!row.rowClass) {
    return row.rowClass
  }
  return ''
}
const changeBtn = (value: any, row: any, option: any) => {
  emit('changeBtn', value, row, option)
};
const setTbodySort = (arr: any, fromIndex: any, toIndex: any) => {
  // 检查索引是否有效
  if (fromIndex < 0 || fromIndex >= arr.length || toIndex < 0 || toIndex > arr.length) {
    console.error('无效的索引');
    return;
  }
  // 使用 splice 方法取出要移动的元素
  const [element] = arr.splice(fromIndex, 1);
  // 在新位置插入该元素
  arr.splice(toIndex - 1, 0, element);
  arr = arr.map((el: any, index: number) => (el[props.sortKey] = index + 1));
};
//复制josn
const copyJsonToClipboard = (json: any) => {
  // 将JSON对象转换为字符串
  const jsonString = JSON.stringify(json, null, 2); // 使用2个空格缩进使输出更易读
  // 创建一个临时元素用于复制内容
  const tempElement = document.createElement('textarea');
  tempElement.value = jsonString;
  // 将临时元素添加到DOM中
  document.body.appendChild(tempElement);
  // 选中并复制文本
  tempElement.select();
  tempElement.setSelectionRange(0, 99999); // 为了移动设备
  try {
    // 使用Clipboard API复制文本到剪贴板
    navigator.clipboard
      .writeText(tempElement.value)
      .then(() => { })
      .catch((err) => { });
  } finally {
    // 移除临时元素
    document.body.removeChild(tempElement);
  }
};
//勾选数据
const handleSelectionChange = (arr: any) => {
  dataInfo.checkboxArr = arr
  emit('tableCheckboxBtn', arr);
};
//单选数据
const tableRadioBtn = (row: any) => {
  emit('tableRadioBtn', row);
};
//更改表头
const headerDragend = (newWidth: number, oldWidth: number, column: any, event: MouseEvent) => {
  emit('headerDragend', column.property, Number(newWidth.toFixed(0)));
};
//单元格单击
const cellClick = (row: any, column: any) => {
  const _text = row[column.property]
  emit('cellClick', column.property, _text);
};
//单元格单击
const clickHeadBtn = (row: any) => {
  if (row.isCanSearch && props.search) {
    props.search.queryDataBaseFiled = row.prop
    props.search.likeWords = ''
  }

};
//列表双击
const rowClick = (row: any, column: any, event: Event) => {
  emit('rowClick', row);
};
//列表双击
const dblclick = (row: any, column: any, event: Event) => {
  const target: any = event.target;
  // 假设你的复选框有特定的类名 'el-checkbox__inner'
  const containsElCheckbox = target.querySelector('.el-checkbox__inner');
  const containsSpecificClass = target.classList.contains('el-checkbox__inner');
  if (containsElCheckbox || containsSpecificClass) return
  if (proxy.selectable && !proxy.selectable(row)) {
    return
  }
  if (props.isRadio) {
    tableRadioBtn(row)
  } else {
    emit('dblclick', row, column);
  }
};
//重新搜索
const searchBtn = () => {
  emit('searchBtn');
};
//更改显示条数
const handleSizeChange = (val: number) => {
  let _search = props.search;
  _search.pageSize = val;
  _search.pageIndex = 1;
  searchBtn();
};
//更改页数
const handleCurrentChange = (val: number) => {
  let _search = props.search;
  _search.pageIndex = val;
  searchBtn();
  nextTick(() => {
    let _search = props.search
    if (_search && _search.pageIndex > 0) {
      let _arr = dataInfo.checkboxList[_search.pageIndex - 1]
      toggleSelection(_arr)
    }
  })
};
//切换多选
const toggleSelection = (rows?: any, ignoreSelectable?: boolean) => {
  const _ref: any = TableRef.value;
  if (rows) {
    if (Array.isArray(rows)) {
      rows.forEach((row: any) => {
        _ref!.toggleRowSelection(row, ignoreSelectable);
      });
    } else {
      _ref!.toggleRowSelection(rows, ignoreSelectable);
    }
  } else {
    _ref!.clearSelection();
  }
  emit('toggleSelection');
};

//排序
import Sortable from 'sortablejs';
//设置排序
const rowDrop = () => {
  // 要拖拽元素的父容器
  const tbody = document.querySelector(`#${props.tableId}  .el-table__body-wrapper tbody`);
  Sortable.create(tbody, {
    //  可被拖拽的子元素
    draggable: `#${props.tableId}  .el-table__row`,
    handle: '.pointer', //可拖拽class
    onEnd(evt: any) {
      emit('onSort', evt);
    },
  });
};
onMounted(() => {
  if (props.sortKey) {
    rowDrop();
  }
});
</script>
<style scoped lang="scss">
.ElTableBox {
  .ElTbodyBox {
    position: relative;
    border-bottom: 1px #f2f4f5 solid;
  }

  .pagination {
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    --m: 8px;

    .tableBox-left {
      display: flex;
      align-items: center;

      >* {
        &:not(:last-child) {
          margin-right: var(--m);
        }

        display: flex;
        align-items: center;

        >* {
          &:not(:last-child) {
            margin-right: var(--m);
          }
        }
      }
    }
  }

  .pointer {
    cursor: pointer;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;

    &:hover {
      color: $primary;
    }
  }
}
</style>
